package com.springboot.ww.platform.pd.order.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpRequest;
import com.springboot.ww.platform.pd.order.constant.PdApiConstants;
import com.springboot.ww.platform.pd.dto.PdStoreTokenVO;
import com.springboot.ww.platform.pd.http.PdHttpProxy;
import com.springboot.ww.platform.pd.http.ResponseMsg;
import com.springboot.ww.platform.pd.order.api.*;
import com.springboot.ww.platform.pd.order.service.IPdProxy;
import com.springboot.ww.platform.pd.util.SignUtil;
import com.ww.springboot.boot.utils.AssertUtil;
import com.ww.springboot.boot.utils.json.JsonUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 描述：
 *
 * @author 🧑 ‍wanwei
 * @since 2024-05-13 18:11
 */
@Service
@AllArgsConstructor
@Slf4j
public class PdProxyImpl implements IPdProxy {

    public final static Map<String, List<String>> warehouseNameMap = new LinkedHashMap() {{
        put("CK0569", Arrays.asList("GC-MD", "GUCANG-MD", "谷仓-美东", "GUCANGMEIDONG", "美东11号", "谷仓11号"));
        put("HWC530630", Arrays.asList("GC-MX", "GUCANG-MX", "谷仓-美西", "美西5号", "谷仓5号", "GUCANGMEIXI"));
        put("USEAST1228", Arrays.asList("ZH-MD", "MEIDONG", "美东", "MD", "EAST"));
        put("USWEST1227", Arrays.asList("ZH-MX", "MEIXI", "美西", "MX", "WEST"));
    }};

    public static final String URL_FORMAT = "https://%s/openapi/router";
    private final static String ADDRESS_KEY = "pd:receiverAddress:";
    private final static String CARRIER_KEY = "pd:carrier:";

    public final static String TOKEN_INVALID_MSG = "access_token is expired or have been refreshed";
    public final static String TOKEN_INVALID_MSG2 = "app_key don't have this api permission";

    public final static String US_DOMAIN = "openapi-b-us.temu.com";
    public final static String US_DOMAIN_KEY = "US";
    public final static String US_OTHER_DOMAIN_KEY = "US_OTHER";
    public final static String US_OTHER_DOMAIN = "openapi-b-global.temu.com";
    private static final String CN_DOMAIN = "openapi.kuajingmaihuo.com";

    private final static String WAREHOUSE_KEY = "pd:warehouse:";

    @Override
    public String getWarehouseId(PdStoreTokenVO storeVO, String warehouseCode) {
        //目前只有美区仓库
        storeVO.setRealDoMain(getDoMainByRegionId(211));
        Map<String, Object> map = new TreeMap<>();
        this.usToken(map, storeVO, PdApiConstants.WAREHOUSE_GET);
        String resultResp = postUS(storeVO, JsonUtil.toJson(map));
        PdWarehouseResp pdWarehouseResp = JsonUtil.parse(resultResp, PdWarehouseResp.class);
        if (pdWarehouseResp == null
                || !pdWarehouseResp.isSuccess()
                || ObjectUtil.isEmpty(pdWarehouseResp.getResult())
                || ObjectUtil.isEmpty(pdWarehouseResp.getResult().getWarehouseList())) {
            throw new RuntimeException("拼多多仓库信息查询接口失败：" + resultResp);
        }
        List<PdWarehouseResp.ResultBean.WarehouseListBean> warehouseListBeans = pdWarehouseResp.getResult().getWarehouseList();
        Optional<PdWarehouseResp.ResultBean.WarehouseListBean> optional = warehouseListBeans.stream()
                .filter(warehouseListBean -> warehouseCode.equals(this.getWarehouseCode(warehouseListBean.getWarehouseName())))
                .findAny();
        if (optional.isPresent()) {
            return optional.get().getWarehouseId();
        }

        throw new RuntimeException("拼多多仓库信息未找到包含【" + warehouseNameMap.get(warehouseCode).toString() + "】标识仓库：" + JsonUtil.toJson(warehouseListBeans));
    }

    private String getWarehouseCode(String warehouseName) {
        warehouseName = warehouseName.toUpperCase();

        for (Map.Entry<String, List<String>> entry : warehouseNameMap.entrySet()) {
            if (entry.getValue().stream().anyMatch(warehouseName::contains)) {
                return entry.getKey();
            }
        }
        return "";
    }


    public final static Map<String, String> DO_MAIN_MAP = new HashMap() {{
        put(US_DOMAIN_KEY, US_DOMAIN);
        put(US_OTHER_DOMAIN_KEY, US_OTHER_DOMAIN);
    }};

    public String getDoMainByRegionId(int regionId) {
        switch (regionId) {
            case 211:
            case 164:
                return US_DOMAIN;
            case 37:
                return US_OTHER_DOMAIN;
            default:
                throw new RuntimeException("regionId未配置域名,请联系管理员");
        }
    }

    public String getDoMainByPlatOrderId(String platOrderId) {
        return getDoMainByRegionId(Integer.valueOf(platOrderId.substring(3, 6)));
    }

    /**
     * 订单
     */
    @Override
    public List<PdOrderListResp.ResultBeanX.ResultBean.PageItemsBean> getOrderList(PdGrabListReq pdGrabListReq, PdStoreTokenVO storeVO) {
        storeVO.setRealDoMain(DO_MAIN_MAP.get(pdGrabListReq.getDoMain()));
        int pageNumber = 1;
        List<PdOrderListResp.ResultBeanX.ResultBean.PageItemsBean> pageItems = new ArrayList<>();
        while (true) {
            Map<String, Object> map = new TreeMap<>();
            map.put("pageNumber", pageNumber);
            map.put("pageSize", "100");
            if (ObjectUtil.isNotEmpty(pdGrabListReq.getPlatOrderIdList())) {
                map.put("parentOrderSnList", JsonUtil.toJson(pdGrabListReq.getPlatOrderIdList()));
            } else {
                map.put("updateAtStart", pdGrabListReq.getBeginTime().getTime() / 1000);
                map.put("updateAtEnd", pdGrabListReq.getEndingTime().getTime() / 1000);
            }
            this.usToken(map, storeVO, PdApiConstants.GET_ORDER_LIST);
            String resultResp = postUS(storeVO, JsonUtil.toJson(map));
            PdOrderListResp pdOrderListResp = JsonUtil.parse(resultResp, PdOrderListResp.class);
            if (pdOrderListResp == null
                    || !pdOrderListResp.isSuccess()
                    || ObjectUtil.isEmpty(pdOrderListResp.getResult())
                    || !pdOrderListResp.getResult().isSuccess()) {
                throw new RuntimeException("拼多多列表查询接口失败：" + resultResp);
            }
            PdOrderListResp.ResultBeanX.ResultBean result = pdOrderListResp.getResult().getResult();
            if (result.getTotalItemNum() == 0 || ObjectUtil.isEmpty(result.getPageItems())) {
                break;
            }
            pageItems.addAll(result.getPageItems());
            if (result.getTotalItemNum() < pageNumber * 100) {
                break;
            }
            pageNumber++;
            //分页不超过100
            if (pageNumber > 100) {
                break;
            }
        }
        return pageItems;
    }

    private String getRealApiUrl(String apiUrl) {
        AssertUtil.notEmpty(apiUrl, "apiUrl不能为空");
        int index = apiUrl.lastIndexOf("//");
        if (index < 0) {
            index = 0;
        } else {
            index += 2;
        }
        apiUrl = apiUrl.substring(index);
        return apiUrl;
    }

    public String postUS(PdStoreTokenVO storeVO, String body) {
        String proxyHost = this.getRealApiUrl(storeVO.getApiUrl());
        HttpPost httpPost = new HttpPost(String.format(URL_FORMAT, ObjectUtil.isNotEmpty(storeVO.getRealDoMain()) ? storeVO.getRealDoMain() : US_DOMAIN));
        StringEntity reqEntity = new StringEntity(body, "UTF-8");
        reqEntity.setContentEncoding("UTF-8");
        reqEntity.setContentType("application/json");
        httpPost.setEntity(reqEntity);
        try {
            ResponseMsg responseMsg = PdHttpProxy.proxyWithRequest(proxyHost, httpPost);
            log.info("拼多多请求：" + proxyHost + "|" + body + " | " + JsonUtil.toJson(responseMsg));
            String regionName = "美区";
            if (US_OTHER_DOMAIN.equals(storeVO.getRealDoMain())) {
                regionName = "全球GLOBAL";
            }
            if (responseMsg.getStatus() != 200 || ObjectUtil.isEmpty(responseMsg.getResult())) {
                throw new RuntimeException("拼多多(" + regionName + ")接口调用失败：" + JsonUtil.toJson(responseMsg));
            } else if (responseMsg.getResult().contains(TOKEN_INVALID_MSG) || responseMsg.getResult().contains(TOKEN_INVALID_MSG2)) {
                throw new RuntimeException("拼多多(" + regionName + ")token失效：" + JsonUtil.toJson(responseMsg));
            }
            return responseMsg.getResult();
        } catch (Exception e) {
            log.info("拼多多请求异常：" + body + " | " + e.getMessage());
            throw e;
        }
    }

    /**
     * 查询收件地址 一个订单一天只能抓取6次 为了避免因为系统异常而导致调用超上限 添加redis缓存 有效期为一天
     *
     * @param platOrderId
     * @param regionId
     * @param storeVO
     * @return
     */
    @Override
    public PdReceiverResp.ResultBeanX.ResultBean getReceiverAddress(String platOrderId, int regionId, PdStoreTokenVO storeVO, boolean throwFlag) {
        storeVO.setRealDoMain(getDoMainByRegionId(regionId));

        Map<String, Object> map = new TreeMap<>();
        map.put("parentOrderSn", platOrderId);
        this.usToken(map, storeVO, PdApiConstants.GET_ORDER_RECEIVER);
        String resultResp = postUS(storeVO, JsonUtil.toJson(map));
        PdReceiverResp pdReceiverResp = JsonUtil.parse(resultResp, PdReceiverResp.class);
        if (pdReceiverResp == null || !pdReceiverResp.isSuccess() || ObjectUtil.isEmpty(pdReceiverResp.getResult())) {
            throw new RuntimeException("拼多多收件人信息查询接口失败：" + resultResp);
        }
        PdReceiverResp.ResultBeanX result = pdReceiverResp.getResult();
        if (result.isSuccess()) {
            return result.getResult();
        }
        if (throwFlag) {
            throw new RuntimeException("拼多多收件人信息查询接口失败：" + resultResp);
        }
        //收件人信息查询不到 不抛异常
        log.error("收件人信息查询失败！{}  {}", platOrderId, resultResp);
        return null;
    }

    @Override
    public String getCarrierId(PdStoreTokenVO storeVO, int regionId, String providerName) {
        storeVO.setRealDoMain(getDoMainByRegionId(regionId));
        String key = CARRIER_KEY + regionId + ":" + providerName;
        //固定的参数 可以加缓存
        Map<String, Object> map = new TreeMap<>();
        map.put("regionId", regionId);
        this.usToken(map, storeVO, PdApiConstants.GET_CARRIER_LIST);
        String resultResp = postUS(storeVO, JsonUtil.toJson(map));
        PdCarrierResp pdCarrierResp = JsonUtil.parse(resultResp, PdCarrierResp.class);
        if (pdCarrierResp == null || !pdCarrierResp.isSuccess() || ObjectUtil.isEmpty(pdCarrierResp.getResult())) {
            throw new RuntimeException("拼多多物流商查询接口失败：" + resultResp);
        }
        Optional<PdCarrierResp.ResultBean> optional = pdCarrierResp.getResult().stream().filter(resultBean -> resultBean.getLogisticsBrandName().equals(providerName)).findFirst();
        if (optional.isPresent()) {
            return optional.get().getLogisticsServiceProviderId();
        }
        throw new RuntimeException(String.format("未匹配到合适的拼多多物流商 %s -> %s", providerName, resultResp));
    }


    /**
     * 暂时只做单个运单发货的功能
     *
     * @param storeVO
     */
    @Override
    public void shipmentConfirm(PdMarkProxyDTO dto, PdStoreTokenVO storeVO) {
        storeVO.setRealDoMain(getDoMainByPlatOrderId(dto.getOrderNumber()));
        PdMarkSendReq pdMarkSendReq = new PdMarkSendReq();
        pdMarkSendReq.setCarrierId(Integer.valueOf(dto.getCarrierId()));
        pdMarkSendReq.setTrackingNumber(dto.getTrackingNumber());
        pdMarkSendReq.setSelfShippingWarehouseId(dto.getSelfShippingWarehouseId());

        List<PdMarkSendReq.OrderSendInfoListBean> sendInfoListBeans = dto.getSkuList().stream().map(sku -> {
            PdMarkSendReq.OrderSendInfoListBean sendInfoListBean = new PdMarkSendReq.OrderSendInfoListBean();
            sendInfoListBean.setGoodsId(sku.getGoodsId());
            sendInfoListBean.setOrderSn(sku.getOrderSn());
            sendInfoListBean.setParentOrderSn(dto.getOrderNumber());
            sendInfoListBean.setQuantity(sku.getQuantity());
            sendInfoListBean.setSkuId(sku.getSkuId());
            return sendInfoListBean;
        }).collect(Collectors.toList());

        pdMarkSendReq.setOrderSendInfoList(sendInfoListBeans);

        Map<String, Object> map = new TreeMap<>();
        map.put("sendType", "0");
        map.put("sendRequestList", JsonUtil.toJson(Arrays.asList(pdMarkSendReq)));
        this.usToken(map, storeVO, PdApiConstants.SHIP_ORDER);
        String resultResp = postUS(storeVO, JsonUtil.toJson(map));
        PdMarkResp pdMarkResp = JsonUtil.parse(resultResp, PdMarkResp.class);
        if (pdMarkResp == null || !pdMarkResp.isSuccess() || pdMarkResp.getResult() == null) {
            throw new RuntimeException("拼多多标发货接口调用失败：" + resultResp);
        }
        if (pdMarkResp.getResult().isSuccess() || Arrays.asList("Order shipped", "订单已发货").contains(pdMarkResp.getErrorMsg())) {
            return;
        }
        throw new RuntimeException("拼多多标发货接口调用失败：" + resultResp);
    }

//    /**
//     * 商品 目前只能根据创建时间拉取listing 无法做增量拉取 直接全量拉
//     */
//    @Override
//    public List<PdListingResp.ResultBean.DataBean> getListingAll(PdStoreTokenVO storeVO, int page) {
//        return getListing(storeVO, page, null);
//    }

    @Override
    public List<PdListingResp.ResultBean.DataBean> getListing(PdStoreTokenVO storeVO, int page, Date timeStart) {
        Map<String, Object> map = new TreeMap<>();
        map.put("pageSize", 20);
        map.put("page", page);
        if (ObjectUtil.isNotEmpty(timeStart)) {
            map.put("createdAtStart", timeStart.getTime() + 1);
            map.put("createdAtEnd", System.currentTimeMillis());
        }
        this.cnToken(map, storeVO, PdApiConstants.GET_GOOD_LIST);
        String s = JsonUtil.toJson(map);
        String body = HttpRequest.post(String.format(URL_FORMAT, CN_DOMAIN)).body(s).execute().body();
        log.info("拼多多拉取listing：" + body + " | " + body);
        if (ObjectUtil.isEmpty(body)) {
            throw new RuntimeException("拼多多拉取listing失败!返回为空");
        }
        PdListingResp pdListingResp = JsonUtil.parse(body, PdListingResp.class);
        if (ObjectUtil.isEmpty(pdListingResp) || !pdListingResp.isSuccess()) {
            throw new RuntimeException("拼多多拉取listing失败!" + body);
        }
        return pdListingResp.getResult().getData();
    }

    @Override
    public PdShipmentResp.ResultBeanX.ResultBean.ShipmentInfoDTOBean getShipmentGet(PdStoreTokenVO storeVO, String parentOrderSn, String orderSn) {
        storeVO.setRealDoMain(getDoMainByPlatOrderId(parentOrderSn));
        Map<String, Object> map = new TreeMap<>();
        map.put("parentOrderSn", parentOrderSn);
        map.put("orderSn", orderSn);
        this.usToken(map, storeVO, PdApiConstants.SHIPMENT_GET);
        String req = JsonUtil.toJson(map);
        String resultResp = postUS(storeVO, req);
        PdShipmentResp pdShipmentResp = JsonUtil.parse(resultResp, PdShipmentResp.class);
        if (pdShipmentResp == null || ObjectUtil.isEmpty(pdShipmentResp.getResult()) || !pdShipmentResp.isSuccess()) {
            throw new RuntimeException("拼多多获取发货详情失败：" + resultResp);
        }
        if (pdShipmentResp.getResult().isSuccess() && ObjectUtil.isEmpty(pdShipmentResp.getResult().getResult().getShipmentInfoDTO())) {
            return null;
        }
        Optional<PdShipmentResp.ResultBeanX.ResultBean.ShipmentInfoDTOBean> optional = Optional.ofNullable(pdShipmentResp)
                .map(PdShipmentResp::getResult)
                .map(resultBean -> resultBean.getResult())
                .map(resultBean -> resultBean.getShipmentInfoDTO())
                .map(list -> list.get(0));
        if (optional.isPresent()) {
            return optional.get();
        }
        throw new RuntimeException("拼多多获取发货详情失败：" + resultResp);
    }

    @Override
    public void shipmentUpdate(PdStoreTokenVO storeVO, String platOrderId, PdMarkUpdateReq pdMarkUpdateReq) {
        storeVO.setRealDoMain(getDoMainByPlatOrderId(platOrderId));
        Map<String, Object> map = new TreeMap<>();
        map.put("editPackageRequestList", Arrays.asList(pdMarkUpdateReq));
        usToken(map, storeVO, PdApiConstants.SHIPMENT_UPDATE);
        String req = JsonUtil.toJson(map);
        String resultResp = postUS(storeVO, req);
        PdShipmentUpdateResp shipmentUpdateResp = JsonUtil.parse(resultResp, PdShipmentUpdateResp.class);
        if (shipmentUpdateResp == null || !shipmentUpdateResp.isSuccess()) {
            throw new RuntimeException("拼多多更新标发货失败：" + resultResp);
        }
    }

    private void cnToken(Map<String, Object> map, PdStoreTokenVO storeVO, String api) {
        map.put("data_type", "JSON");
        map.put("access_token", storeVO.getTokenCn());
        String sign = SignUtil.pd(map, storeVO.getAppKeyCn(), storeVO.getAppSecretCn(), api);
        map.put("sign", sign);
    }

    private void usToken(Map<String, Object> map, PdStoreTokenVO storeVO, String api) {
        map.put("data_type", "JSON");
        if (US_DOMAIN.equals(storeVO.getRealDoMain())) {
            map.put("access_token", storeVO.getToken());
        } else if (US_OTHER_DOMAIN.equals(storeVO.getRealDoMain())) {
            map.put("access_token", ObjectUtil.isNotEmpty(storeVO.getTokenGlobal()) ? storeVO.getTokenGlobal() : storeVO.getToken());
        }
        String sign = SignUtil.pd(map, storeVO.getAppKey(), storeVO.getAppSecret(), api);
        map.put("sign", sign);
    }

    @Override
    public List<PdUnShipPackageResp.ResultDTO.UnshippedPackageDTO> getUnShipPackageResp(PdStoreTokenVO storeVO) {
        List<PdUnShipPackageResp.ResultDTO.UnshippedPackageDTO> list = new ArrayList<>();
        int pageNumber = 1;
        while (true) {
            Map<String, Object> map = new TreeMap<>();
            map.put("pageNumber", pageNumber);
            map.put("pageSize", "50");
            usToken(map, storeVO, PdApiConstants.UN_SHIPPED_PACKAGE_GET);
            String req = JsonUtil.toJson(map);
            String resultResp = postUS(storeVO, req);
            PdUnShipPackageResp resp = JsonUtil.parse(resultResp, PdUnShipPackageResp.class);
            if (resp == null || !resp.getSuccess()) {
                throw new RuntimeException("待发货列表查询失败：" + resultResp);
            }
            if (ObjectUtil.isEmpty(resp.getResult().getUnshippedPackage())) {
                return list;
            }
            list.addAll(resp.getResult().getUnshippedPackage());
            pageNumber++;
        }

    }

    @Override
    public String packageConfirm(PdStoreTokenVO token, PdShippedConfirmReq pdShippedConfirmReq) {
        Map<String, Object> map = new TreeMap<>();
        map.put("packageSendInfoList", Arrays.asList(pdShippedConfirmReq));
        usToken(map, token, PdApiConstants.SHIPPED_PACKAGE_CONFIRM);
        String req = JsonUtil.toJson(map);
        String resultResp = postUS(token, req);
        PdPackageConfirmResp pdPackageConfirmResp = JsonUtil.parse(resultResp, PdPackageConfirmResp.class);
        if (pdPackageConfirmResp != null && pdPackageConfirmResp.getSuccess()) {
            return resultResp;
        }
        if (ObjectUtil.isNotEmpty(pdPackageConfirmResp.getErrorMsg()) && pdPackageConfirmResp.getErrorMsg().contains("Order shipped")) {
            return resultResp;
        }
        throw new RuntimeException("待发货包裹确认发货失败：" + resultResp);
    }
}
